#include"scheduler.h"
#include"time.h"
#include"stdlib.h"
#include"stdio.h"

void print_array_list(array_list*);

Process* nextRRProcess(Scheduler* the_scheduler){
  return bqueue_dequeue(the_scheduler->ready_queue);
}
Process* nextPRProcess(Scheduler* the_scheduler){
  Process* item;
  bqueue* temp_q;
  int i = 0;
  for(i = PRIORITY_VERY_HIGH; i >= PRIORITY_VERY_LOW;i--){
    temp_q = the_scheduler->ready_priority_queue[i];
    if(temp_q->q->backing_store->size > 0){
      item = bqueue_dequeue(temp_q);
      break;
    }
  }
  return item;
}

Process* nextLOProcess(Scheduler* the_scheduler){
  barray_list tickets;
  int i,j = 0;
  Process* temp;
  printf("\nArray before nextPRoc.");
  print_array_list(the_scheduler->ready_arr_queue->al);

  pthread_mutex_lock(the_scheduler->lock);
  barray_list_init(&tickets, 1);

  for(i=0;i<the_scheduler->ready_arr_queue->al->size;i++){
    temp = (Process*)barray_list_get(the_scheduler->ready_arr_queue, i);
    for(j = 0 ;j < temp->priority + 1; j++){
      barray_list_add(&tickets, i);
    }
  }

  srand(time(NULL));

  i = rand() % tickets.al->size;
  i = barray_list_get(&tickets, i);


  temp = barray_list_remove(the_scheduler->ready_arr_queue, i);

  pthread_mutex_unlock(the_scheduler->lock);

  barray_list_destroy(&tickets);

  print_array_list(the_scheduler->ready_arr_queue->al);
  printf("\nArray after nextProc.");

  return temp;
}

void readyRRProc(Scheduler* the_scheduler, Process* the_proc){
  bqueue_enqueue(the_scheduler->ready_queue, the_proc);
}
void readyPRProc(Scheduler* the_scheduler, Process* the_proc){
  bqueue_enqueue(the_scheduler->ready_priority_queue[the_proc->priority], the_proc);
}
void readyLOProc(Scheduler* the_scheduler, Process* the_proc){
  printf("\nArray before readying.");
  print_array_list(the_scheduler->ready_arr_queue->al);
  pthread_mutex_lock(the_scheduler->lock);
  barray_list_add(the_scheduler->ready_arr_queue, the_proc);
  pthread_mutex_unlock(the_scheduler->lock);
  print_array_list(the_scheduler->ready_arr_queue->al);
  printf("\nArray after readying.");
}

int schedulerInit(Scheduler* the_scheduler, SchedulerType the_type){
  int rv,i = 0;

  the_scheduler->type = the_type;
  the_scheduler->lock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
  pthread_mutex_init(the_scheduler->lock, NULL);

  switch(the_type){
  case ROUND_ROBIN:
    the_scheduler->ready_queue = (bqueue*)malloc(sizeof(bqueue));
    bqueue_init(the_scheduler->ready_queue);
    the_scheduler->next_proc = &nextRRProcess;
    the_scheduler->ready_process = &readyRRProc;
    break;
  case PRIORITY:
    the_scheduler->ready_priority_queue = (bqueue**)malloc(sizeof(bqueue*) * 5);
    for(i = 0; i < 5; i++){
      the_scheduler->ready_priority_queue[i] = (bqueue*)malloc(sizeof(bqueue));
      bqueue_init(the_scheduler->ready_priority_queue[i]);
    }
    the_scheduler->next_proc = &nextPRProcess;
    the_scheduler->ready_process = &readyPRProc;
    break;
  case LOTTERY:
    the_scheduler->ready_arr_queue = (barray_list*)malloc(sizeof(barray_list));
    barray_list_init(the_scheduler->ready_arr_queue, 4);
    the_scheduler->next_proc = &nextLOProcess;
    the_scheduler->ready_process = &readyLOProc;
    break;
  }
  return rv;
}

void print_array_list(array_list* the_array_list){
  int i = 0;
  char* proc_type;
  printf("\nArrayList: head->");
  for(i=0;i< the_array_list->size;i++){
    proc_type = procTypeToString(((Process*)array_list_get(the_array_list, i))->t);
    printf("[%s]%s",proc_type, i == (the_array_list->size - 1) ? "":"," );
  }
  printf("<-tail");
}

